home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / compress / tar321__.zip / SOURCES.ZIP / ASPI.C < prev    next >
C/C++ Source or Header  |  1997-03-30  |  28KB  |  879 lines

  1. #include "modern.h"
  2. #ifdef MSDOS
  3. #include <stdio.h>
  4. #include "pctimer.h"
  5. #include "define.h"
  6. #include <string.h>
  7.  
  8. extern void timeslice();
  9.  
  10. #define NILTIME 0
  11. #define MINTIME 6 /* ~0.3s */
  12. #define TRESET  (unsigned short)SEC2TICK(3)
  13. #define MIDTIME (unsigned short)SEC2TICK(10)
  14. #define HALTCPU {if (!(id.flags & SLOW_RUN)) timeslice();}
  15.  
  16. #define MAXLEX        8
  17. #define UNKNOWN 255
  18.  
  19. void far (*ASPI_ptr)(void far *) = (void far (*)())0xffff0000L;
  20. extern int ASPI_entry(void far (* far *)());
  21.  
  22. #define HA_INQ          0 /* host adapter inquiry            */
  23. #define GET_TYPE  1 /* get device type                           */
  24. #define EXEC_SIO  2 /* execute SCSI I/O command    */
  25. #define ABORT_SRB 3 /* abort SCSI I/O command           */
  26. #define RESET_DEV 4 /* reset SCSI device                   */
  27. #define SET_HAP   5 /* set host adapter parameters */
  28. #define GET_DI          6 /* get disk drive information  */
  29.  
  30. #define TAPE          1 /* SCSI device type */
  31.  
  32. #ifndef byte
  33. #        define byte unsigned char
  34. #endif
  35. #define SRBHEAD byte command, status, adapter, flags, reserved[4]
  36. #define MAX_CDB   6  /* Group 0 commands only */
  37. #define MAX_SENCE 14 /* ??? */
  38.  
  39. struct _srbinquiry {
  40.    SRBHEAD, ha_total, ha_type, mgr_id[16], ha_id[16], hap[16];
  41. };
  42. struct _srbgettype {
  43.    SRBHEAD, target, lun, devtype;
  44. };
  45. struct _srbabort {
  46.    SRBHEAD, pointer[4];
  47. };
  48. struct _srbio {
  49.    SRBHEAD, target, lun,
  50.    datalength[4], sencelength, databuffer[4], srblink[4], cdblength,
  51.    adapter_status, target_status, post_routine[4],
  52.    workspace[34], area[MAX_CDB + MAX_SENCE];
  53. };
  54. struct _srbreset {
  55.    SRBHEAD, target, lun, dummy[14],
  56.    adapter_status, target_status, post_routine[4], workspace[34];
  57. };
  58. struct _cdbtape {
  59.    byte opcode, unit, counter[3], control;
  60. };
  61.  
  62. /* SCSI tape opcodes */
  63. #define S0P_TEST   0  /* test unit ready */
  64. #define S0P_REWIND 1
  65. #define S0P_LIMITS 5  /* read block limits */
  66. #define S0P_READ   8
  67. #define S0P_WRITE  10
  68. #define S0P_WFM    16 /* write file mark */
  69. #define S0P_SPACE  17
  70. #define S0P_INQ    18
  71. #define S0P_MODE   21 /* mode select */
  72. #define S0P_ERASE  25
  73. #define S0P_MSENCE 26 /* mode sence */
  74.  
  75. /* Transfer direction bits */
  76. #define T_INHERIT 000 /* Command-dependent*/
  77. #define T_READ          010 /* Read from target */
  78. #define T_WRITE   020 /* Write to target  */
  79. #define T_NONE          030 /* No data transfer */
  80.  
  81. #define LONG_ERASE   1
  82. #define IMMED_RETURN 2
  83.  
  84. #define ASPI_EMPTY        0
  85. #define ASPI_QUEUED        0
  86. #define ASPI_SUCCESS        1
  87. #define ASPI_SENCE        2
  88. #define ASPI_ABORTED        2
  89. #define ASPI_BUSY       8
  90. #define ASPI_INVALID        0x80 /* illegal request */
  91. #define ASPI_NoHA        0x81 /* invalid host adapter */
  92. #define ASPI_ABSENT        0x82 /* device not installed */
  93. #define SCSI_SENCE        0x20
  94. #define SCSI_SENCEOK        0x20
  95. #define SCSI_RECOVER        0x21
  96. #define SCSI_BUSY       0x22
  97. #define SCSI_INVALID        0x25 /* illegal request */
  98. #define SCSI_ATTN        0x26 /* unit attention */
  99. #define SCSI_BLANK        0x28
  100. #define SCSI_ILI        0x35 /* incorrect length indicator */
  101. #define SCSI_EOM        0x36 /* end-of-medium */
  102. #define SCSI_FM         0x37 /* hit file mark */
  103.  
  104. int aspierrno;
  105. struct { byte code; char *text; } aspierrlist[] = {
  106.    { 0x00, "SCSI request in progress"            },
  107.    { 0x01, "SCSI request completed without error"},
  108.    { 0x02, "SCSI request aborted by host"        },
  109.    { 0x04, "SCSI request completed with error"   },
  110.    { 0x08, "Specified Target/LUN is busy"        },
  111.    { 0x11, "Selection timeout"                   },
  112.    { 0x12, "Data over-run/under-run"             },
  113.    { 0x13, "Unexpected Bus Free"                 },
  114.    { 0x14, "Target bus phase sequence failure"   },
  115.    { 0x18, "Reservation conflict"                },
  116.  
  117.    { 0x20, "No sence"          }, /* My codes */
  118.    { 0x21, "Recovered error"   },
  119.    { 0x22, "Not ready"         },
  120.    { 0x23, "Medium error"      },
  121.    { 0x24, "Hardware error"    },
  122.    { 0x25, "Illegal request"   },
  123.    { 0x26, "Unit attention"    },
  124.    { 0x27, "Data protect"      },
  125.    { 0x28, "Blank check"       },
  126.    { 0x29, "Vendor unique"     },
  127.    { 0x2A, "Copy aborted"      },
  128.    { 0x2b, "Aborted command"   },
  129.    { 0x2C, "Equal"             },
  130.    { 0x2d, "Volume overflow"   },
  131.    { 0x2E, "Miscompare"        },
  132.    { 0x2f, "Reserved sence key"},
  133.  
  134.    { 0x35, "Incorrect length"  },
  135.    { 0x36, "End of medium"     },
  136.    { 0x37, "File mark reached" },
  137.  
  138.    { 0x80, "Invalid SCSI request"       }, /* ASPI codes again */
  139.    { 0x81, "Invalid Host Adapter Number"},
  140.    { 0x82, "SCSI device not installed"  },
  141. };
  142.  
  143. char *aspierrmsg(int n)
  144. {
  145.    static char h[16] = "0123456789ABCDEF";
  146.    static char vendor[] = "Vendor unique, class ? code ?h";
  147.    static char other[] = "Error ??h";
  148.    register i;
  149.  
  150.    for (i=0; i<sizeof(aspierrlist)/sizeof(aspierrlist[0]); i++) {
  151.       if (aspierrlist[i].code == n) return aspierrlist[i].text;
  152.    }
  153.    if (n >= 0x70 && n <= 0xff) {
  154.       vendor[21] = n >= 0xf0 ? '0' : h[(n >> 4) & 7];
  155.       vendor[28] = h[n & 15];
  156.       return vendor;
  157.    }
  158.    other[6] = h[(n >> 4) & 15];
  159.    other[7] = h[ n       & 15];
  160.    return other;
  161. }
  162.  
  163. #define END_OF_MEDIUM 0x80
  164. #define FIXED_MODE    1
  165. #define NO_RESET      2
  166. #define NO_REWIND     4
  167. #define ERASE         8
  168. #define FM_ON_CLOSE   0x10
  169. #define SLOW_RUN      0x20
  170. #define OPEN_FLAGS    0x3E
  171.  
  172. static struct {
  173.    unsigned long iosize;
  174.    unsigned long maxblock; unsigned short minblock;
  175.    byte adapter, target, lun, density, flags;
  176. } id = { -1L, 0, 0, 4, 0, 0, 0 };
  177. static long residue;
  178. static byte lastcmd = 0;
  179. static byte ok_to_close = FALSE;
  180. static unsigned to_skip = 0;
  181. static unsigned short maxtime = SEC2TICK(30);
  182. static eraseflags = 0;
  183.  
  184. int aspicall(struct _srbio *s, unsigned timeout)
  185. {
  186.    unsigned long t0;
  187.    struct _srbabort sa;
  188.    register unsigned char *p;
  189.  
  190.    *(long *)(s->reserved) = 0L; /* clear reserved field */
  191.    (*ASPI_ptr)((void far *)s);
  192.    if (s->status != ASPI_QUEUED || timeout == 0) goto test;
  193.    for (t0 = pctimer();;) {
  194.      if (s->status != ASPI_QUEUED) goto test;
  195.      if (pctimer() - t0 > timeout) break;
  196.      HALTCPU;
  197.    }
  198.    /* Timeout expired - abort the request */
  199.    sa.command = ABORT_SRB;
  200.    sa.adapter = s->adapter;
  201.    sa.flags   = 0;
  202.    *(long *)sa.reserved = 0L;
  203.    *(void far * far *)sa.pointer = (void far *)s;
  204.    (void)(*ASPI_ptr)((void far *)&sa);
  205.    /* Wait till IO aborted */
  206.    for (t0=pctimer(); 1 >= pctimer()-t0;) HALTCPU;
  207.    if (s->status == ASPI_QUEUED) s->status = ASPI_ABORTED;
  208. test:
  209.    if (s->status & 0x80) return s->status;
  210.    if (s->adapter_status != ASPI_EMPTY) return s->adapter_status;
  211.    if (s->target_status  != ASPI_EMPTY) {
  212.       /* Is sence area information available? */
  213.       if (s->target_status != ASPI_SENCE) return s->target_status;
  214.       if (s->command == EXEC_SIO) {
  215.          p = s->area + s->cdblength;
  216.          /* Take out vendor-unique classes (remap class 0 to 15) */
  217.          if ((*p & 0x70) == 0x00) return *p | 0xf0;
  218.          if ((*p & 0x70) != 0x70) return *p | 0x80;
  219.          /* Take out vendor-unique codes */
  220.          if ((*p & 0x0f) != 0x00) return *p & 0x7f;
  221.          /* Is incorrect length indicator set? */
  222.          if (p[2] & 0x20) return SCSI_ILI;
  223.          /* Is nontrivial sence key available? */
  224.          if (p[2] & 0x0E) return (p[2] & 15) | SCSI_SENCE;
  225.          /* Check for file mark and end-of-medium conditions */
  226.          if (p[2] & 0x80) return SCSI_FM;
  227.          if (p[2] & 0x40) return SCSI_EOM;
  228.          /* Nothing looks like an error */
  229.          return (p[2] & 15) | SCSI_SENCE;
  230.       }
  231.    }
  232.    return s->status;
  233. }
  234.  
  235. int aspisio(int cmd, void *buffer, long length, long cmdlen,
  236.             unsigned aspiflags, unsigned cdbflags, unsigned tout)
  237. {
  238.    register k;
  239.    register byte *p;
  240.    struct _srbio s;
  241.  
  242.    s.command = EXEC_SIO;
  243.    s.adapter = id.adapter;
  244.    s.flags   = aspiflags;
  245.    *(long *)(s.reserved) = 0L;
  246.    s.target  = id.target;
  247.    s.lun     = id.lun;
  248.    *(long *)(s.datalength) = length;
  249.    s.sencelength = MAX_SENCE;
  250.    *(void far * far *)(s.databuffer) = (void far *)buffer;
  251.    *(long *)(s.srblink) = 0L;
  252.    s.cdblength = 6; /* Group 0 commands only */
  253.    *(long *)(s.post_routine) = 0xffff0000L;
  254.  
  255.    ((struct _cdbtape *)(s.area))->opcode = lastcmd = cmd;
  256.    ((struct _cdbtape *)(s.area))->unit = (id.lun << 5) | cdbflags;
  257.    ((struct _cdbtape *)(s.area))->counter[0] = (byte)(cmdlen >> 16);
  258.    ((struct _cdbtape *)(s.area))->counter[1] = (byte)(cmdlen >> 8);
  259.    ((struct _cdbtape *)(s.area))->counter[2] = (byte) cmdlen;
  260.    ((struct _cdbtape *)(s.area))->control = 0;
  261.  
  262.    /* Clear sence area */ *(p = s.area + s.cdblength) = 0;
  263.  
  264.    k = aspicall(&s, tout);
  265.    if (k & SCSI_SENCE && k < 0x70) {
  266.       /* Check sence data area */
  267.       if (p[2] & 0x40) id.flags |= END_OF_MEDIUM;
  268.       else             id.flags &= ~END_OF_MEDIUM;
  269.       residue = (p[6] | ((unsigned)p[5] << 8)) |
  270.          ((long)(p[4] | ((unsigned)p[3] << 8)) << 16);
  271.    }
  272.    return k;
  273. }
  274.  
  275. int aspiexec(int cmd, unsigned cdbflags, unsigned tout)
  276. {
  277.    return aspisio(cmd, NULL, 0L, 0L, T_NONE, cdbflags, tout);
  278. }
  279.  
  280. int aspitrans(int wr, void *buffer, unsigned length)
  281. {
  282.    register k;
  283.    unsigned fixed, counter;
  284.  
  285.    if (id.iosize != 0L) {/* fixed mode */
  286.       if (length % id.iosize) return (aspierrno=SCSI_ILI, -1);
  287.       counter = (unsigned)(length / id.iosize);
  288.       fixed = 1;
  289.    } else {
  290.       if (length < id.minblock || length > id.maxblock)
  291.          return (aspierrno=SCSI_ILI, -1);
  292.       counter = length;
  293.       fixed = 0;
  294.    }
  295.    if (wr) {
  296.       wr = S0P_WRITE; k = T_WRITE;
  297.    } else {
  298.       wr = S0P_READ;  k = T_READ;
  299.    }
  300.    k = aspisio(wr, buffer, (long)length, (long)counter, k, fixed, maxtime);
  301.    if (k == ASPI_SUCCESS) return length;
  302.    if (k != SCSI_SENCEOK && k != SCSI_RECOVER && k != SCSI_BLANK &&
  303.        k != SCSI_EOM && k != SCSI_FM) return (aspierrno=k, -1);
  304.    if (!residue) return length;
  305.    aspierrno = k;
  306.    if (fixed) {
  307.       if (residue > 0x10000L/id.minblock) return -1;
  308.       residue *= id.minblock;
  309.    }
  310.    return (unsigned long)residue > length ? -1 : length - (int)residue;
  311. }
  312.  
  313. long aspiinvoke(int cmd, long counter, int flag)
  314. {
  315.    register k;
  316.  
  317.    k = aspisio(cmd, NULL, 0L, counter, T_NONE, flag, maxtime);
  318.    if (k == ASPI_SUCCESS) return 0L;
  319.    if (k != SCSI_SENCEOK && k != SCSI_RECOVER && k != SCSI_BLANK &&
  320.        k != SCSI_EOM && k != SCSI_FM) return (aspierrno=k, -0x80000000L);
  321.    if (residue) aspierrno = k;
  322.    return residue;
  323. }
  324.  
  325. int aspirewind(void)
  326. {
  327.    register k;
  328.  
  329.    if (v_flag > 1) {
  330.       fputs("Rewind... ", myout); fflush(myout);
  331.    }
  332.    k=aspiexec(S0P_REWIND,0,maxtime);
  333.    if (v_flag > 1) fprintf(myout, "Done (k = 0x%02x)\n", k);
  334.    if (k != ASPI_SUCCESS) {
  335.       if ((k != SCSI_SENCEOK && k != SCSI_EOM && k != SCSI_FM) ||
  336.          !(id.flags & END_OF_MEDIUM)) return (aspierrno=k);
  337.    }
  338.    return ASPI_SUCCESS;
  339. }
  340.  
  341. int aspierase(int lbit)
  342. {
  343.    register k;
  344.  
  345.    if (v_flag > 1) {
  346.       fputs("Erase... ", myout); fflush(myout);
  347.    }
  348.    k = aspiexec(S0P_ERASE, lbit, maxtime);
  349.    if (v_flag > 1) fprintf(myout, "Done (k = 0x%02x)\n", k);
  350.    if (k!=ASPI_SUCCESS && k!=SCSI_SENCEOK && k!=SCSI_EOM)
  351.       return (aspierrno=k);
  352.    return ASPI_SUCCESS;
  353. }
  354.  
  355. int aspireset(void)
  356. {
  357.    struct _srbreset s;
  358.    unsigned long t0;
  359.    register i;
  360.  
  361.    s.command = RESET_DEV;
  362.    s.adapter = id.adapter;
  363.    s.flags   = 0;
  364.    s.target  = id.target;
  365.    s.lun     = id.lun;
  366.    for (i=0; i<sizeof(s.dummy); i++) s.dummy[i] = 0;
  367.    *(long *)(s.post_routine) = 0xffff0000L;
  368.    *(long *)(s.reserved) = 0L; /* clear reserved field */
  369.    (*ASPI_ptr)((void far *)&s);
  370.    for (t0 = pctimer(); s.status == ASPI_QUEUED;) {
  371.       if (pctimer() - t0 > TRESET) break;
  372.       HALTCPU;
  373.    }
  374.    if (!(s.status & 0x80)) {
  375.       if (s.adapter_status != ASPI_EMPTY) return s.adapter_status;
  376.       if (s.target_status  != ASPI_EMPTY) return s.target_status;
  377.    }
  378.    return s.status;
  379. }
  380.  
  381. int aspiread(char *buffer, unsigned length)
  382. {
  383.    register k;
  384.  
  385.    if (!cblock) {
  386.       if      (length > id.maxblock) length = (unsigned)id.maxblock;
  387.       else if (length < id.minblock) length = (unsigned)id.minblock;
  388.    }
  389.    if ((k = aspitrans(0, buffer, length)) == -1) {
  390.       (void)fprintf(stderr, "Tar: ASPI read error: %s\n",
  391.          aspierrmsg(aspierrno));
  392.    }
  393.    return k;
  394. }
  395.  
  396. int aspiwrite(char *buffer, unsigned length)
  397. {
  398.    register k;
  399.  
  400.    if (id.flags & END_OF_MEDIUM && lastcmd == S0P_WRITE) {
  401.       aspierrno = SCSI_EOM; k = 0;
  402.    } else {
  403.       k = aspitrans(1, buffer, length);
  404.    }
  405.    if (k != length) {
  406.       (void)fprintf(stderr, "Tar: ASPI write error: %s\n",
  407.          aspierrmsg(aspierrno));
  408.    }
  409.    return k;
  410. }
  411.  
  412. int aspiback(/* number of 512-byte blocks */ int n)
  413. {
  414.    if (aspiinvoke(S0P_SPACE, -1, 0) != 0L) {
  415.       (void)fprintf(stderr, "Tar: ASPI seek error: %s\n",
  416.          aspierrmsg(aspierrno));
  417.       return 0;
  418.    }
  419.    return n;
  420. }
  421.  
  422. static int GetType(void)
  423. {
  424.    struct _srbgettype s;
  425.  
  426.    s.command = GET_TYPE;
  427.    s.adapter = id.adapter;
  428.    s.target  = id.target;
  429.    s.lun     = id.lun;
  430.    s.flags   = 0;
  431.    *(long *)(s.reserved) = 0L;
  432.    (*ASPI_ptr)((void far *)&s);
  433.    if (s.status == ASPI_SUCCESS) return s.devtype;
  434.    aspierrno = s.status;
  435.    return -1;
  436. }
  437.  
  438. static int HAInquiry(struct _srbinquiry *s, int adapter)
  439. {
  440.    s->command = HA_INQ;
  441.    s->adapter = adapter;
  442.    s->flags   = 0;
  443.    *(long *)(s->reserved) = 0L;
  444.    (*ASPI_ptr)((void far *)s);
  445.    return s->status;
  446. }
  447.  
  448. int aspicount(int devno)
  449. {
  450.    register k;
  451.    struct _srbinquiry s;
  452.    register ha_max;
  453.  
  454.    /* Initialise device description */
  455.    id.maxblock = 0x800000L;
  456.    id.minblock = 1;
  457.  
  458.    /* Get number of host adapters */
  459.    if ((k=HAInquiry(&s, 0)) != ASPI_SUCCESS) return k;
  460.    ha_max = s.ha_total;
  461.  
  462.    /* Search for the tape device with given number */
  463.    for (id.adapter = 0; id.adapter < ha_max; id.adapter ++)
  464.       for (id.target = 0; id.target < 8; id.target ++)
  465.          for (id.lun = 0; id.lun < 8; id.lun ++) {
  466.             if ((k = GetType()) == -1) {
  467.                if (aspierrno != ASPI_ABSENT) return aspierrno;
  468.             } else if (k == TAPE) {
  469.                if (devno-- == 0) goto found;
  470.             }
  471.          }
  472.    /* There is no so many tape devices */ return ASPI_ABSENT;
  473. found:
  474.    return ASPI_SUCCESS;
  475. }
  476.  
  477. static int hex(register c)
  478. {
  479.    if           (c>='0' && c<='9') c -= '0';
  480.    else if (c>='A' && c<='F') c -= 'A'-10;
  481.    else if (c>='a' && c<='f') c -= 'a'-10;
  482.    else c = ERROR;
  483.    return c;
  484. }
  485.  
  486. static int rstrlen(char *s, int size)
  487. {
  488.    register i;
  489.    for (i=0; s[i] && i<size; i++) {
  490.       if (s[i] < ' ' || s[i] >= 127) return 0;
  491.    }
  492.    while (i>0 && (s[i-1]==' ' || s[i-1]=='\377')) --i;
  493.    return i;
  494. }
  495.  
  496. int aspiparse(char *s)
  497. {
  498.    static char already[] = "tape format already defined";
  499.    static struct { unsigned short nqic, code; } qiclist[] = {
  500.       {11,4}, {120,15}, {150,16}, {320,17}, {525,17}, {1350,18}
  501.    };
  502.    char lex[MAXLEX+1], *errmsg;
  503.    register i, k; register char *p;
  504.  
  505.    for (i=0; i<sizeof(lex) && *s!='.'; i++) {
  506.       if (*s == '\0' || *s == ':' || *s == ';' || *s == ',') goto test_name;
  507.       lex[i] = *s++;
  508.    }
  509.    return FALSE;
  510. test_name:
  511.    lex[i] = '\0';
  512.    if ((lex[0] & ~('z'^'Z')) != 'A' || strnicmp(lex,"ASPI",4)) return FALSE;
  513.    if (lex[4]!='\0' && stricmp(lex+4,"MGR$") && stricmp(lex+4,"TAPE"))
  514.       return FALSE;
  515.  
  516.    to_skip           = 0;
  517.    ok_to_close = FALSE;
  518.    maxtime     = SEC2TICK(30);
  519.    eraseflags  = 0;
  520.    id.maxblock = 0x800000L;
  521.    id.minblock = 1;
  522.    id.adapter  = UNKNOWN;
  523.    id.target   = UNKNOWN;
  524.    id.lun      = UNKNOWN;
  525.    id.density  = 0;
  526.    id.flags    = 0;
  527.  
  528.    if (*s) {
  529.       while (*++s) {
  530.          for (i=0; i<=MAXLEX; ++i, s++) {
  531.             if      (*s >= 'A' && *s <= 'Z') lex[i] = *s | ('z'^'Z');
  532.             else if (*s >= 'a' && *s <= 'z') lex[i] = *s;
  533.             else break;
  534.          }
  535.          if (i < 1 || i > MAXLEX) {
  536.             errmsg = "device parameter error"; goto error;
  537.          }
  538.          lex[i] = '\0'; /* for diagnostic printing */
  539.          if (!strncmp("fluent", lex, i)) {
  540.             id.flags |= NO_RESET;
  541.          } else if (!strncmp("norewind", lex, i)) {
  542.             if (to_skip || id.flags & ERASE) goto mutual;
  543.             id.flags |= NO_REWIND;
  544.          } else if (!strncmp("erase", lex, i)) {
  545.             if (to_skip || id.flags & NO_REWIND) goto mutual;
  546.             id.flags |= ERASE;
  547.          } else if (i>1 && !strncmp("slow", lex, i)) {
  548.             id.flags |= SLOW_RUN;
  549.             maxtime = SEC2TICK(300);
  550.             eraseflags = LONG_ERASE;
  551.          } else if (!strncmp("qic", lex, i)) {
  552.             if (id.density) {
  553.                errmsg = already; goto error;
  554.             }
  555.             if (*s == '-') {
  556.                ++s;
  557.             } else {
  558.                if (*s == ':') ++s;
  559.                if (*s == '=') ++s;
  560.             }
  561.             for (k=0, i=0; i<5 && *s>='0' && *s<='9'; ++s, i++)
  562.                k = (*s - '0') + 10*k;
  563.             if (i < 5)
  564.                for (i=0; i<dimof(qiclist); i++)
  565.                   if (qiclist[i].nqic == k) {
  566.                      id.density = qiclist[i].code; break;
  567.                   }
  568.             if (!id.density) {
  569.                errmsg = "invalid QIC number"; goto error;
  570.             }
  571.          } else {
  572.             if (*s == ':') ++s;
  573.             if (*s == '=') ++s;
  574.             if (strncmp("adapter", lex, i) == 0) {
  575.                if (*s<'0' || *s>'7') {
  576.                   errmsg = "invalid adapter number"; goto error;
  577.                }
  578.                id.adapter = *s++ & 7;
  579.             } else if (strncmp("target", lex, i) == 0) {
  580.                if (*s<'0' || *s>'7') {
  581.                   errmsg = "invalid target number"; goto error;
  582.                }
  583.                id.target = *s++ & 7;
  584.             } else if (strncmp("lun", lex, i) == 0) {
  585.                if (*s<'0' || *s>'7') {
  586.                   errmsg = "invalid LUN number"; goto error;
  587.                }
  588.                id.lun = *s++ & 7;
  589.             } else if (!strncmp("skip", lex, i)) {
  590.                if (id.flags & (ERASE|NO_REWIND)) goto mutual;
  591.                for (to_skip=0, i=0; i<5 && *s>='0' && *s<='9'; ++i, s++) {
  592.                   to_skip = (*s - '0') + 10*to_skip;
  593.                }
  594.             } else if (!strncmp("code", lex, i) ||
  595.                        !strncmp("density", lex, i)) {
  596.                id.density = 0; p = s;
  597.                if (*p == '0') ++p;
  598.                if ((*p | ('z'^'Z')) == 'x') {
  599.                   for (i=0, s=p+1; i<2; ++s, i++) {
  600.                      if ((k = hex(*s)) == ERROR) break;
  601.                         id.density = k | (id.density << 4);
  602.                      }
  603.                } else {
  604.                   while (hex(*p)!=ERROR) ++p;
  605.                   if ((*p | ('z'^'Z')) == 'h') {
  606.                      for (i=0; i<2; ++s, i++) {
  607.                        if ((k = hex(*s)) == ERROR) break;
  608.                        id.density = k | (id.density << 4);
  609.                      }
  610.                      if ((*s | ('z'^'Z')) == 'h') ++s;
  611.                   } else {/* decimal code */
  612.                      for (i=0; i<4 && *s>='0' && *s<='9'; ++i, s++) {
  613.                         id.density = (*s - '0') + 10*id.density;
  614.                      }
  615.                   }
  616.                }
  617.                if (!i || ~255 & id.density) {
  618.                   errmsg = "invalid density code"; goto error;
  619.                }
  620.             } else {
  621.                (void)fprintf(stderr,"Tar: unknown parameter \'%s\'\n",lex);
  622.                return ERROR;
  623.             }
  624.          }
  625.          if (*s == '\0') break;
  626.          if (*s != ',' && *s != ':' && *s != '.') {
  627.             (void)fprintf(stderr,"Tar: invalid character after \'%s\'\n",lex);
  628.             return ERROR;
  629.          }
  630.       }
  631.    }
  632.    if (ASPI_entry((void far *)&ASPI_ptr) != 0) {
  633.       errmsg = "no ASPI manager found"; goto error;
  634.    }
  635.    if (setdrive ||
  636.       (id.adapter==UNKNOWN && id.target==UNKNOWN && id.lun==UNKNOWN)) {
  637.       if (id.adapter!=UNKNOWN || id.target!=UNKNOWN || id.lun!=UNKNOWN) {
  638.          errmsg = "both device number and SCSI parameters specified";
  639.          goto error;
  640.       }
  641.       if ((k=aspicount(ndrive)) != ASPI_SUCCESS) {
  642.          errmsg = k!=ASPI_ABSENT ? aspierrmsg(k) :
  643.                   "there is no so many tape devices" ;
  644.          goto error;
  645.       }
  646.    } else {
  647.       if (id.target == UNKNOWN) {
  648.          errmsg = "unknown target number"; goto error;
  649.       }
  650.       if (id.adapter == UNKNOWN) id.adapter = 0;
  651.       if (id.lun     == UNKNOWN) id.lun = 0;
  652.       if ((k=GetType()) != TAPE) {
  653.          errmsg = k == -1 ? aspierrmsg(k) : "not a tape device specified";
  654.          goto error;
  655.       }
  656.    }
  657.    if (v_flag) {
  658.       struct _srbinquiry s;
  659.       if (HAInquiry(&s, id.adapter) != ASPI_SUCCESS) goto reported;
  660.  
  661.       i = rstrlen((char*)s.mgr_id, 16);
  662.       k = rstrlen((char*)s.ha_id,  16);
  663.       if (!i && !k) goto reported;
  664.  
  665.       (void)fprintf(myout, "Tar: ");
  666.       if (i) {
  667.          (void)fprintf(myout, "ASPI manager: <%-.*s>", i, s.mgr_id);
  668.          if (k) (void)fprintf(myout, ", ");
  669.       }
  670.       if (k) {
  671.          (void)fprintf(myout, "SCSI adapter: <%-.*s>", k, s.ha_id);
  672.       }
  673.       (void)fprintf(myout, "\n");
  674. reported:;
  675.    }
  676.    if (a_flag && !(id.flags & NO_REWIND)) id.flags |= FM_ON_CLOSE;
  677.    return TRUE;
  678. mutual:
  679.    errmsg = "\'erase\', \'norewind\' and \'skip\' are mutaully exclusive";
  680. error:
  681.    (void)fprintf(stderr, "Tar: %s\n", errmsg);
  682.    return ERROR;
  683. }
  684.  
  685. static void printape(void)
  686. {
  687.    char b[96];
  688.    int dlen, ilen=0, plen=0, rlen=0;
  689.  
  690.    /* Inquiry command does not interfere with 'Unit Attension' */
  691.    if (aspisio(S0P_INQ, b, 96L, 96L, T_READ, 0, MINTIME) != ASPI_SUCCESS)
  692.       return;
  693.    if ((dlen = *(unsigned char *)(b+4) + 5) > 8) {
  694.       ilen = rstrlen(b+8,  8);
  695.       if (dlen > 16) {
  696.          plen = rstrlen(b+16, 16);
  697.          if (dlen > 32) rlen = rstrlen(b+32, 4);
  698.       }
  699.    }
  700.    if (ilen || plen || rlen) {
  701.       (void)fprintf(myout, "Tar: SCSI tape drive: ");
  702.       if (ilen) (void)fprintf(myout, "%-8.*s", ilen, b+8);
  703.       if (plen) (void)fprintf(myout, ", model %-.*s", plen, b+16);
  704.       if (rlen) (void)fprintf(myout, ", rev. %-.*s", rlen, b+32);
  705.       (void)fprintf(myout, "\n");
  706.    }
  707. }
  708.  
  709. int aspisetmode(long bsize, int speed, int bm, int pf)
  710. {
  711.    unsigned char b[12];
  712.  
  713.    b[1] = b[0] = 0;
  714.    b[2] = (unsigned char)speed;
  715.    if (bm) b[2] |= 16;
  716.    b[3] = 8; /* block descriptor length */
  717.  
  718.    b[4] = id.density;
  719.    b[7] = b[6] = b[5] = 0; /* whole tape */
  720.    b[8] = 0; /* reserved */
  721.    b[ 9] = (unsigned char)(255 & (bsize >> 16));
  722.    b[10] = (unsigned char)(255 & (bsize >> 8));
  723.    b[11] = (unsigned char)(255 &  bsize);
  724.    return aspisio(S0P_MODE, b, 12L, 12L, T_WRITE, (pf ? 16 : 0), MINTIME);
  725. }
  726.  
  727. static int longrewind(void)
  728. /* Wait until previous operation completed and rewind */
  729. {
  730.    register i, k;
  731.    unsigned long t0;
  732.  
  733.    for (i=0, t0=pctimer();;) {
  734.       if ((k=aspirewind()) == SCSI_ATTN) {
  735.          if (++i < 7) continue;
  736.       } else if (k == ASPI_BUSY || k == SCSI_BUSY) {
  737.          if (pctimer() - t0 < maxtime) continue;
  738.       }
  739.       break;
  740.    }
  741.    return k;
  742. }
  743.  
  744. int aspistart(void)
  745. {
  746.    register k;
  747.    unsigned long t0;
  748.    unsigned char b[12];
  749.    int gotBL = FALSE, gotMS = FALSE;
  750.    extern void printbs(int);
  751.  
  752.    if (!(id.flags & (NO_RESET|NO_REWIND)) && id.density != 127) {
  753.       (void)aspireset();
  754.       /* Wait until POST and/or clear 'unit attension' condition */
  755.       for (k=0, t0=pctimer();;) {
  756.          switch (aspiexec(S0P_TEST, 0, MINTIME)) {
  757.             case SCSI_ATTN: if (++k < 7) continue; break;
  758.             case ASPI_BUSY:
  759.             case SCSI_BUSY: if (pctimer() - t0 < maxtime) continue;
  760.          }
  761.          break;
  762.       }
  763.    }
  764.    if (v_flag) printape();
  765.    if (!(id.flags & NO_REWIND)) {
  766.       if (longrewind() != ASPI_SUCCESS) goto error;
  767.       if (id.flags & ERASE) {
  768.          if (aspierase(eraseflags) != ASPI_SUCCESS) goto error;
  769.          if (aspirewind() != ASPI_SUCCESS) goto error;
  770.       }
  771.    }
  772.    id.iosize = 0L;
  773.    /* Read block limits */
  774.    k = aspisio(S0P_LIMITS, b, 6L, 0L, T_READ, 0, MINTIME);
  775.    if (k == ASPI_SUCCESS || k == SCSI_SENCEOK || k == SCSI_EOM) {
  776.       id.minblock = b[5] | ((unsigned)b[4] << 8);
  777.       id.maxblock = b[3] | ((unsigned)b[2] << 8) | ((unsigned long)b[1]<<16);
  778.       if (!id.maxblock) id.maxblock = 0x00ffffffL;
  779.       gotBL = TRUE;
  780.    }
  781.    k = aspisio(S0P_MSENCE, b, 12L, 12L, T_READ, 0, MINTIME);
  782.    if ((k == ASPI_SUCCESS || k == SCSI_SENCEOK || k == SCSI_EOM) &&
  783.        b[0] >= 11 /* was 12, fixed 1997/1/19 NBB */ && b[3] == 8) {
  784.       id.iosize = ((unsigned long)b[9]<<16) | ((unsigned)b[10]<<8) | b[11];
  785.       gotMS = TRUE;
  786.       if (gotBL && id.iosize != 0L) {
  787.          if (id.iosize < id.minblock || id.iosize > id.maxblock) {
  788.             (void)fprintf(stderr,
  789.                "Tar: SCSI blocksize %ld is out of hardware limits (%u-%ld)\n",
  790.                id.iosize, id.minblock, id.maxblock);
  791.             return ERROR;
  792.          }
  793.          if (!cblock && id.iosize%BLKSIZE == 0 &&
  794.              id.iosize <= BLKSIZE*MAXBLOCK) {
  795.             printbs(cblock = (int)(id.iosize / BLKSIZE));
  796.             goto ok;
  797.          }
  798.       }
  799.    }
  800.    if (gotMS && id.iosize == 0L || !gotMS &&
  801.        gotBL && id.minblock != id.maxblock) {
  802.       id.flags &= ~FIXED_MODE;
  803.       id.iosize = 0L;
  804.       if (cblock) {
  805.          if ((k = cblock * BLKSIZE) < id.minblock || k > id.maxblock) {
  806.             (void)fprintf(stderr,
  807.                "Tar: blocksize is out of hardware limits (%d - %ld)\n",
  808.                id.minblock / BLKSIZE, id.maxblock / BLKSIZE);
  809.             return ERROR;
  810.          }
  811.       } else if (c_flag) {
  812.          printbs(cblock = id.maxblock < BLKSIZE*MAXBLOCK ?
  813.                     (int)(id.maxblock/BLKSIZE) : MAXBLOCK);
  814.       }
  815.    } else if (gotMS || gotBL) {
  816.       id.flags |= FIXED_MODE;
  817.       if (!gotMS) id.iosize = id.minblock;
  818.       if ((id.iosize % BLKSIZE || id.iosize > BLKSIZE*MAXBLOCK) &&
  819.           (!cblock || id.density==0 || id.density==127)) {
  820.          (void)fprintf(stderr,
  821.             "Tar: hardware blocksize %ld bytes is not suitable for tar\n",
  822.             id.iosize);
  823.       }
  824.       if (cblock) {
  825.          if (id.density!=0 && id.density!=127 &&
  826.              (k = cblock*BLKSIZE) >= id.minblock && k <= id.maxblock) {
  827.             id.iosize = k;
  828.          } else if ((cblock*BLKSIZE) % id.iosize) {
  829.             (void)fprintf(stderr,
  830.                "Tar: blocksize must be multiple of %ld\n",
  831.                id.iosize/BLKSIZE);
  832.          }
  833.       } else {
  834.          printbs(cblock = (int)(id.iosize / BLKSIZE));
  835.       }
  836.    } else /* !gotMS && !gotBL */ {
  837.       if (cblock) {
  838.          id.iosize = id.maxblock = id.minblock = BLKSIZE*cblock;
  839.          id.flags |= FIXED_MODE;
  840.       } else {
  841.          id.maxblock = BLKSIZE*MAXBLOCK;
  842.          id.minblock = BLKSIZE;
  843.          id.flags &= ~FIXED_MODE;
  844.          id.iosize = 0L;
  845.       }
  846.    }
  847. ok:
  848.    if (id.density!=0 && id.density != 127) {
  849.       for (k=4; k--;) {
  850.          if (aspisetmode(id.iosize, 0, k&2, k&1)
  851.             != SCSI_INVALID) break;
  852.       }
  853.    }
  854.    ok_to_close = TRUE;
  855.    if (to_skip) {
  856.       if (aspisio(S0P_SPACE, NULL, 0L, (long)to_skip, T_NONE, 1, maxtime)
  857.          != ASPI_SUCCESS) goto error;
  858.    }
  859.    return 0;
  860. error:
  861.    (void)fprintf(stderr, "Tar: %s\n", aspierrmsg(aspierrno));
  862.    return ERROR;
  863. }
  864.  
  865. void aspiend(void)
  866. {
  867.    if (!ok_to_close) return;
  868.    if (id.flags & FM_ON_CLOSE || lastcmd == S0P_WRITE) {
  869.       if (aspiinvoke(S0P_WFM,
  870.             ((id.flags & (FM_ON_CLOSE|NO_REWIND)) == FM_ON_CLOSE ? 1L : 0L),
  871.             0) != 0L) goto error;
  872.    }
  873.    if (id.flags & NO_REWIND) return;
  874.    if (longrewind() == ASPI_SUCCESS) return;
  875. error:
  876.    (void)fprintf(stderr, "Tar: %s\n", aspierrmsg(aspierrno));
  877. }
  878. #endif
  879.